home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
strategy
/
xpat2-1.000
/
xpat2-1
/
xpat2-1.04
/
src
/
hints.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-09
|
8KB
|
306 lines
/*****************************************************************************/
/* */
/* */
/* X patience version 2 -- module hints.c */
/* */
/* Functions for the ``display hint'' part */
/* written by Heiko Eissfeldt and Michael Bischoff */
/* see COPYRIGHT.xpat2 for Copyright details */
/* */
/* */
/*****************************************************************************/
#include "xpatgame.h"
#define RESET_HINTS (-2)
#define ALL_HINTS (-1)
static Move lasthint;
void cmd_DoHint(void) {
if (lasthint == NO_MOVE) {
show_message(TXT_NOHINTGIVEN);
} else {
store_move(do_move(SRCIND(lasthint), DSTPILE(lasthint)));
}
}
#define MAXHINTS 256
static struct hintstruct {
int srcind, dstpile;
int value;
} hinttab[MAXHINTS];
static int hints, showhint; /* hints is number of hints in table (-1: unknown), showhint is index */
static int hintcmp(const void *a, const void *b)
{ return ((const struct hintstruct *)b)->value - ((const struct hintstruct *)a)->value;
}
/* ind == -1 => no marked cards, show all possible moves
otherwise show move for block ind */
static void collect_hints(Cardindex ind)
{
int begsrcpile, endsrcpile;
int pile;
if (ind != ALL_HINTS) {
begsrcpile = endsrcpile = getpile(ind);
} else {
begsrcpile = 0;
endsrcpile = game.numpiles-1;
}
/* gather all possibilities, if necessary */
hints = 0;
for (pile = begsrcpile; pile <= endsrcpile; pile++) {
int dstpile, uppercard, stacksrc, havestack;
/* check all moves which go from this pile */
/* if pile is empty, no moves are possible */
if (EMPTY(pile))
continue;
if (pile == IDECK && !(rules.variant & DECK_VISIBLE))
continue;
/* if there is a block selected already, use it */
/* otherwise, take the maximum number of movable cards */
uppercard = (ind == ALL_HINTS) ? maxsequence(pile, INDEX_OF_FIRST_CARD(pile)) : ind;
if (game.piletype[pile] == Stack)
stacksrc = -1; /* avoid stack to stack moves */
else {
stacksrc = stackable(pile);
if (ind != ALL_HINTS && stacksrc != uppercard)
stacksrc = -1; /* block differs => no moves to stack */
}
havestack = 0;
for (dstpile = 0; dstpile < game.numpiles; ++dstpile) {
/* in a first step, reject some moves */
int srcindex;
if (rules.variant & HINTS_LESSER)
if (pile <= dstpile)
break;
if (pile == dstpile)
continue;
switch (game.piletype[dstpile]) {
case Slot:
if (EMPTY(dstpile)) {
if ((rules.move_bits & ES_MASK) != ES_KINGS)
continue; /* don't fill empty slots, if allowed for all */
/* now: ugly code! */
/* kings may be moved, if they don't come from a stack */
/* and they don't leave an empty slot */
if (game.piletype[pile] == Stack && ind == ALL_HINTS)
continue;
if (game.piletype[pile] == Slot && game.ind[pile] == uppercard)
continue;
/* king's move allowed! */
}
if (IS_JOKER(game.cards[INDEX_OF_LAST_CARD(dstpile)]))
continue; /* don't move to jokers */
/* fall through */
srcindex = uppercard;
break;
case Tmp:
case FaceupDeck:
case FacedownDeck:
continue;
case Stack: /* for stacks, choose another srcindex */
if (stacksrc == -1 || havestack)
continue;
srcindex = stacksrc;
break;
default:
srcindex = 0; /* to keep compiler happy */
exit(EXIT_FAILURE); /* cannot happen! */
}
if (move_valid(srcindex, dstpile)) {
/* hint found. store source and destination, if acceptable */
hinttab[hints].value = rules.good_hint ?
(*rules.good_hint)(srcindex, dstpile) : 100; /* 100 is default value */
if (hinttab[hints].value) {
if (hinttab[hints].value < 2 && ind == ALL_HINTS) {
/* don't suggest bad moves */
continue;
}
/* accept the hint */
if (game.piletype[dstpile] == Stack && !(rules.variant & STACKS_MULTI))
havestack = 1;
hinttab[hints].srcind = srcindex;
hinttab[hints].dstpile = dstpile;
if (++hints == MAXHINTS)
break;
}
}
}
}
/* sort hints by relevance */
qsort(hinttab, (size_t)hints, sizeof(hinttab[0]), hintcmp);
showhint = hints; /* will show either first or last hint */
}
/* this function returns a value (the higher the better) of the move done (or 0, if no move) */
int generic_automove(Cardindex srcindex) /* pile is "movable" */
{ Pileindex i, srcpile;
cmd_ResetHints();
collect_hints(srcindex);
if (hints) {
store_move(do_move(hinttab[0].srcind, hinttab[0].dstpile));
return hinttab[0].value;
}
/* no move to non-empty piles possible, try to move to empty slot */
srcpile = getpile(srcindex);
for (i = game.numpiles - 1; i >= 0; --i) {
if (i == srcpile)
continue;
if (game.piletype[i] == Tmp && game.piletype[srcpile] == Tmp)
continue;
if (move_valid(srcindex, i)) {
store_move(do_move(srcindex, i));
return 1;
}
}
cmd_ResetHints(); /* MUST reset the hints! */
return 0; /* no move => extremely ugly */
}
static void mysprintf(char *p, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
while (*fmt) {
if (*fmt != '%')
*p++ = *fmt++;
else {
int arg;
arg = va_arg(args, int);
switch (*++fmt) {
case 'R':
strcpy(p, TXT_RANK[RANK(arg)]);
p += strlen(p);
break;
case 'S':
strcpy(p, TXT_SUIT[SUIT(arg)]);
p += strlen(p);
break;
case 'P':
switch(game.piletype[arg]) {
case FaceupDeck:
strcpy(p, TXT_DECK);
break;
case FacedownDeck:
strcpy(p, TXT_IDECK);
break;
case Slot:
strcpy(p, TXT_SLOT);
p += strlen(p);
sprintf(p, " %d", arg - rules.numstacks + 1);
break;
case Stack:
strcpy(p, TXT_STACK);
p += strlen(p);
sprintf(p, " %d", arg + 1);
break;
case Tmp:
strcpy(p, TXT_TMP);
p += strlen(p);
sprintf(p, " %d", arg-rules.numstacks-rules.numslots + 1);
break;
}
p += strlen(p);
break;
default:
*p++ = *fmt;
}
++fmt;
}
}
va_end(args);
*p = '\0';
}
static void display_hint(struct hintstruct *p) {
int dstpile, srcpile, srcval;
char buf[180];
dstpile = p->dstpile;
srcpile = getpile(p->srcind);
srcval = game.cards[p->srcind];
mysprintf(buf, TXT_CANMOVE, srcpile, srcval, srcval, dstpile);
show_message(buf);
show_arrow(True);
}
static int forward = 1;
static int hint(Cardindex ind, boolean dodisplay) {
show_arrow(False); /* if any arrow visible, clear it */
if (ind == RESET_HINTS) {
hints = showhint = -1;
game.arrow_srcind = -1;
game.arrow_dstpile = -1;
lasthint = NO_MOVE;
return 0;
}
/* printf("hints = %d\n", hints); */
if (hints < 0)
collect_hints(ind);
if (!hints) {
if (dodisplay)
show_message(TXT_NOHINTS);
return 0;
} else {
showhint = (forward ? (showhint + 1) : (showhint + hints)) % (hints+1);
if (showhint == hints)
show_message(TXT_WRAPPING);
else {
struct hintstruct *p;
p = hinttab + showhint;
game.arrow_srcind = p->srcind;
game.arrow_dstpile = p->dstpile;
lasthint = MOVE(p->srcind, p->dstpile);
if (dodisplay)
display_hint(p);
}
return 1;
}
}
void cmd_ResetHints(void) {
hint(RESET_HINTS, 0);
}
void cmd_AllMoves(void) {
forward = 1;
hint(RESET_HINTS, 0);
while (hint(ALL_HINTS, 0)) {
/* XFlush(dpy); */
cmd_DoHint();
/* XFlush(dpy); */
}
}
void cmd_NextHint(void) { /* show next hint in queue */
forward = 1;
if (game.srcind < 0)
hint(ALL_HINTS, 1);
else
hint(game.srcind, 1);
}
void cmd_PreviousHint(void) { /* show previous hint */
forward = 0;
if (game.srcind < 0)
hint(ALL_HINTS, 1);
else
hint(game.srcind, 1);
}